package com.zyao89.view.zloading.ball;

import com.zyao89.view.zloading.util.NumCalcUtil;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.utils.Color;
import ohos.app.Context;

import java.util.LinkedList;

/**
 * ElasticBallBuilder
 *
 * @author jjy
 * @since 2021-03-22
 */
public class ElasticBallBuilder extends BaseBallBuilder {
    // 最终阶段
    private static final int FINAL_STATE = 2;

    // 小球共5个位置
    private static final int SUM_POINT_POS = 5;

    // 背景圆集合
    private final LinkedList<CirclePoint> mBGCircles = new LinkedList<>();

    // 动画间隔时间
    private long mDurationTime = 333;
    private float mBallR;
    private Path mPath;

    // 当前动画阶段
    private int mCurrAnimatorState = 0;

    // 每个小球的偏移量
    private float mCanvasTranslateOffset;

    // 当前状态是否翻转
    private boolean mIsReverse = false;

    // 当前小球的位置
    private int mCurrPointPos = 0;

    @Override
    protected void initParams(Context context, Color color) {
        mBallR = getAllSize() / SUM_POINT_POS;
        mCanvasTranslateOffset = getIntrinsicWidth() / SUM_POINT_POS;
        mPath = new Path();

        initPaint(5, color);
        initPoints(mBallR);
        initBgPoints();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawBG(canvas);
        drawBall(canvas);
    }

    /**
     * 背景圆点初始化
     */
    private void initBgPoints() {
        float centerX = getViewCenterX();
        float centerY = getViewCenterY();
        CirclePoint p_0 = new CirclePoint(NumCalcUtil.subtract(centerX, mCanvasTranslateOffset * 2), centerY);
        CirclePoint p_1 = new CirclePoint(NumCalcUtil.subtract(centerX, mCanvasTranslateOffset), centerY);

        // 默认第一个圆不显示
        mBGCircles.add(p_0);
        mBGCircles.add(p_1);
        CirclePoint p_2 = new CirclePoint(centerX, centerY);
        CirclePoint p_3 = new CirclePoint(NumCalcUtil.add(centerX, mCanvasTranslateOffset), centerY);
        CirclePoint p_4 = new CirclePoint(NumCalcUtil.add(centerX, mCanvasTranslateOffset * 2), centerY);
        mBGCircles.add(p_2);
        mBGCircles.add(p_3);
        mBGCircles.add(p_4);
        p_0.setEnabled(false);
    }

    /**
     * 绘制小球
     *
     * @param canvas
     */
    private void drawBall(Canvas canvas) {
        canvas.save();
        mPaint.setStyle(Paint.Style.FILLANDSTROKE_STYLE);
        float offsetX = mBGCircles.size() / 2f * mCanvasTranslateOffset;
        canvas.translate(NumCalcUtil.add(-offsetX, mCanvasTranslateOffset * mCurrPointPos), 0);
        super.drawBall(canvas, mPath, mPaint);
        canvas.restore();
    }

    /**
     * 绘制背景圆
     *
     * @param canvas
     */
    private void drawBG(Canvas canvas) {
        canvas.save();
        mPaint.setStyle(Paint.Style.STROKE_STYLE);
        for (CirclePoint point : mBGCircles) {
            point.draw(canvas, mBallR, mPaint);
        }
        canvas.restore();
    }

    @Override
    protected void prepareStart(AnimatorValue floatValueAnimator) {
        mDurationTime = ceil(getAnimationDuration() * 0.3f);
        floatValueAnimator.setDuration(mDurationTime);
    }

    @Override
    protected void prepareEnd() {

    }

    @Override
    protected void computeUpdateValue(AnimatorValue animation, float animatedValue) {
        float offset = mCanvasTranslateOffset;
        int currState = mIsReverse ? mCurrAnimatorState + 3 : mCurrAnimatorState;
        switch (currState) {
            case 0:
                animation.setDuration(mDurationTime + 1000);
                mBallPoints.get(5).setOffsetX(animatedValue * offset);
                mBallPoints.get(6).setOffsetX(animatedValue * offset);
                mBallPoints.get(7).setOffsetX(animatedValue * offset);
                break;
            case 1:
                animation.setDuration(mDurationTime + 1111);
                mBallPoints.get(2).setOffsetX(animatedValue * offset);
                mBallPoints.get(3).setOffsetX(animatedValue * offset);
                mBallPoints.get(4).setOffsetX(animatedValue * offset);
                mBallPoints.get(8).setOffsetX(animatedValue * offset);
                mBallPoints.get(9).setOffsetX(animatedValue * offset);
                mBallPoints.get(10).setOffsetX(animatedValue * offset);
                break;
            case 2:
                animation.setDuration(mDurationTime + 1333);
                mBallPoints.get(0).setOffsetX(animatedValue * offset);
                mBallPoints.get(1).setOffsetX(animatedValue * offset);
                mBallPoints.get(11).setOffsetX(animatedValue * offset);
                break;
            case 3:
                animation.setDuration(mDurationTime + 1000);
                mBallPoints.get(0).setOffsetX(NumCalcUtil.subtract(1, animatedValue) * offset);
                mBallPoints.get(1).setOffsetX(NumCalcUtil.subtract(1, animatedValue) * offset);
                mBallPoints.get(11).setOffsetX(NumCalcUtil.subtract(1, animatedValue) * offset);
                break;
            case 4:
                animation.setDuration(mDurationTime + 1111);
                mBallPoints.get(2).setOffsetX(NumCalcUtil.subtract(1, animatedValue) * offset);
                mBallPoints.get(3).setOffsetX(NumCalcUtil.subtract(1, animatedValue) * offset);
                mBallPoints.get(4).setOffsetX(NumCalcUtil.subtract(1, animatedValue) * offset);
                mBallPoints.get(8).setOffsetX(NumCalcUtil.subtract(1, animatedValue) * offset);
                mBallPoints.get(9).setOffsetX(NumCalcUtil.subtract(1, animatedValue) * offset);
                mBallPoints.get(10).setOffsetX(NumCalcUtil.subtract(1, animatedValue) * offset);
                break;
            case 5:
                animation.setDuration(mDurationTime + 1333);
                mBallPoints.get(5).setOffsetX(NumCalcUtil.subtract(1, animatedValue) * offset);
                mBallPoints.get(6).setOffsetX(NumCalcUtil.subtract(1, animatedValue) * offset);
                mBallPoints.get(7).setOffsetX(NumCalcUtil.subtract(1, animatedValue) * offset);
                break;
            default:
                break;
        }
    }

    @Override
    public void onRepeat(Animator animator) {
        if (++mCurrAnimatorState > FINAL_STATE) { // 还原到第一阶段
            mCurrAnimatorState = 0;

            /* 小球位置改变 */
            if (mIsReverse) { // 倒序
                mCurrPointPos--;
            } else { // 顺序
                mCurrPointPos++;
            }

            /* 重置并翻转动画过程 */
            if (mCurrPointPos >= SUM_POINT_POS - 1) { // 倒序
                mIsReverse = true;
                mCurrPointPos = SUM_POINT_POS - 2;
                for (int i = 0; i < mBGCircles.size(); i++) {
                    CirclePoint point = mBGCircles.get(i);
                    if (i == mBGCircles.size() - 1) {
                        point.setEnabled(true);
                    } else {
                        point.setEnabled(false);
                    }

                }
            } else if (mCurrPointPos < 0) { // 顺序
                mIsReverse = false;
                mCurrPointPos = 0;
                for (int i = 0; i < mBGCircles.size(); i++) {
                    CirclePoint point = mBGCircles.get(i);
                    if (i == 0) {
                        point.setEnabled(false);
                    } else {
                        point.setEnabled(true);
                    }

                }
            }

            // 每个阶段恢复状态，以及对背景圆的控制
            if (mIsReverse) { // 倒序
                // 恢复状态
                for (CirclePoint point : mBallPoints) {
                    point.setOffsetX(mCanvasTranslateOffset);
                }
                mBGCircles.get(mCurrPointPos + 1).setEnabled(true);
            } else { // 顺序
                // 恢复状态
                for (CirclePoint point : mBallPoints) {
                    point.setOffsetX(0);
                }
                mBGCircles.get(mCurrPointPos).setEnabled(false);
            }
        }
    }

}
